﻿using System;
using System.Collections.Generic;
using System.Drawing;
using System.IO;
using System.Text;
using AlgorytmyGenetyczne;
using AlgorytmyGenetyczne.Algorytmy;
using AlgorytmyGenetyczne.Historia;
using AlgorytmyGenetyczne.Operatory;
using AlgorytmyGenetyczne.WarunkiStopu;
using Funkcje;
using Wykres2D;
using Wykres3D;

namespace AlgorytmyGenetyczneGUI
{
    partial class FormAlgorytmyGenetyczne
    {
        private int indeksPopulacjiHistorii = -1;
        private PAG algorytmGenetyczny;

        public int IndeksPopulacjiHistorii
        {
            get { return indeksPopulacjiHistorii; }
        }

        public void kliknietoStart()
        {
            userControlSterowanie.zmienStan();
            Rozwiazanie rozwiazanie = null;
            int numerNajlepszegoBadania = 0;
            int iloscPokolenNajlepszego = 0;
            int iloscBadan = Int32.Parse(userControlSterowanie.textBoxLiczbaBadan.Text);
            long znacznik = DateTime.Now.Ticks;
            string sciezka = userControlStatystyka.SciezkaZapisuStatystyk + znacznik+"\\";
            zapiszFunkcjeDoPliku(sciezka, znacznik.ToString(), userControlParametry.Funkcja.ToString());
            double sumaWynikow = 0.0;
            for (int i = 0; i < iloscBadan; i++)
            {
                //uruchom algorytm
                indeksPopulacjiHistorii = -1;
                algorytmGenetyczny = new PAG(userControlParametry.Kodowania);
                algorytmGenetyczny.WielkoscPopulacji = userControlParametry.WielkoscPopulacji;
                algorytmGenetyczny.Funkcja = userControlParametry.Funkcja;
                algorytmGenetyczny.PrawdopodobienstwoMutacji = userControlParametry.PrawdopodobienstwoMutacji;
                algorytmGenetyczny.WarunekStopu = new WarunekStopuIloscPokolen(userControlParametry.IloscPokolen);
                algorytmGenetyczny.PrawdopodobienstwoKrzyzowania = userControlParametry.PrawdopodobienstwoKrzyzowania;
                algorytmGenetyczny.Historia = new Historia(userControlStatystyka.InterwalStatystyk,
                                                           userControlStatystyka.InterwalHistoriiPopulacji);
                ((SelekcjaRuletki) algorytmGenetyczny.Selekcja).Elitarnosc = userControlParametry.SukcesjaElitarna;
                ((SelekcjaRuletki) algorytmGenetyczny.Selekcja).WielkoscElity = userControlParametry.WielkoscElity;
                Rozwiazanie rozwiazanieAktualne = algorytmGenetyczny.ewolucja();
                sumaWynikow += rozwiazanieAktualne.Wartosc;
                if (rozwiazanie == null || rozwiazanieAktualne.Wartosc > rozwiazanie.Wartosc)
                {
                    rozwiazanie = rozwiazanieAktualne;
                    numerNajlepszegoBadania = i;
                    iloscPokolenNajlepszego = algorytmGenetyczny.Historia.LicznikKrokow;
                }
                algorytmGenetyczny.Historia.zapiszDoPliku(sciezka, znacznik.ToString(), (i + 1).ToString());
                algorytmGenetyczny.Historia.zapiszPopulacjeDoPliku(sciezka,
                                                                   znacznik.ToString(), (i + 1).ToString());
                zapiszWynikDoPliku(sciezka, znacznik.ToString(), rozwiazanieAktualne, algorytmGenetyczny.Historia.LicznikKrokow, i + 1);
            }
            zapiszSredniWynikDoPliku(sciezka, znacznik.ToString(), sumaWynikow/(double)iloscBadan);
            userControlSterowanie.zmienStan();
            formWynik = new FormWynik();
            string wynik = rozwiazanie + " osiągnięty w " + iloscPokolenNajlepszego +
                           " pokoleniach w badaniu " + (numerNajlepszegoBadania + 1);
            formWynik.aktualizujWartosci(wynik);
            formWynik.Show();
        }

        private void zapiszFunkcjeDoPliku(string sciezka, string znacznik, string funkcja)
        {
            FileInfo fileInfo = new FileInfo(sciezka);
            DirectoryInfo directoryInfo = fileInfo.Directory;
            Directory.CreateDirectory(sciezka);
            FileStream fileStream = new FileStream(directoryInfo.FullName + "\\" + znacznik + "rozw.txt", FileMode.Append, FileAccess.Write);
            StreamWriter streamWriter = new StreamWriter(fileStream);
            streamWriter.WriteLine(funkcja);
            streamWriter.WriteLine("========================");
            streamWriter.WriteLine();
            streamWriter.Close();
        }

        private void zapiszWynikDoPliku(string sciezka, string znacznik, Rozwiazanie rozwiazanie, int iloscPokolen, int numerBadania)
        {
            StringBuilder wiersz = new StringBuilder(numerBadania + "\t" + rozwiazanie.Wartosc + "\t" + iloscPokolen);
            foreach (double argument in rozwiazanie.Argumenty)
            {
                wiersz.Append("\t").Append(argument.ToString());
            }

            FileInfo fileInfo = new FileInfo(sciezka);
            DirectoryInfo directoryInfo = fileInfo.Directory;

            FileStream fileStream = new FileStream(directoryInfo.FullName + "\\" + znacznik + "rozw.txt", FileMode.Append, FileAccess.Write);
            StreamWriter streamWriter = new StreamWriter(fileStream);
            streamWriter.WriteLine(wiersz);
            streamWriter.Close();

        }

        private void zapiszSredniWynikDoPliku(string sciezka, string znacznik, double sredniWynik)
        {

            FileInfo fileInfo = new FileInfo(sciezka);
            DirectoryInfo directoryInfo = fileInfo.Directory;

            FileStream fileStream = new FileStream(directoryInfo.FullName + "\\" + znacznik + "rozw.txt", FileMode.Append, FileAccess.Write);
            StreamWriter streamWriter = new StreamWriter(fileStream);
            streamWriter.WriteLine();
            streamWriter.WriteLine("Średni wynik:");
            streamWriter.WriteLine(sredniWynik);
            streamWriter.Close();
        }

        #region Metody wywolujace odpowiednia metode wykresu

        public void pokazWykres()
        {
            if (userControlParametry.IloscParametrow == 1)
            {
                pokazWykres2D();
            }
            else if (userControlParametry.IloscParametrow == 2)
            {
                pokazWykres3D();
            }
        }

        public void poprzedniePokolenieWykres()
        {
            if (userControlParametry.IloscParametrow == 1)
            {
                poprzedniePokolenieWykres2D();
            }
            else if (userControlParametry.IloscParametrow == 2)
            {
                poprzedniePokolenieWykres3D();
            }
        }

        public void nastepnePokolenieWykres()
        {
            if (userControlParametry.IloscParametrow == 1)
            {
                nastepnePokolenieWykres2D();
            }
            else if (userControlParametry.IloscParametrow == 2)
            {
                nastepnePokolenieWykres3D();
            }
        }

        public void poczatkowePokolenieWykres()
        {
            if (userControlParametry.IloscParametrow == 1)
            {
                poczatkowePokolenieWykres2D();
            }
            else if (userControlParametry.IloscParametrow == 2)
            {
                poczatkowePokolenieWykres3D();
            }
        }

        public void koncowePokolenieWykres()
        {
            if (userControlParametry.IloscParametrow == 1)
            {
                koncowePokolenieWykres2D();
            }
            else if (userControlParametry.IloscParametrow == 2)
            {
                koncowePokolenieWykres3D();
            }
        }


        public void zamknijWykres()
        {
            if (userControlParametry.IloscParametrow == 1)
            {
                zamknijWykres2D();
            }
            else if (userControlParametry.IloscParametrow == 2)
            {
                zamknijWykres3D();
            }
        }
        #endregion

        #region Wykres2D
        private void pokazWykres2D()
        {
            formWykres2D = new FormWykres2D();
            formWykres2D.Wykres.PoczatekDziedziny = userControlParametry.PoczatekDziedziny[0];
            formWykres2D.Wykres.KoniecDziedziny = userControlParametry.KoniecDziedziny[0];
            formWykres2D.Wykres.Funkcja = userControlParametry.Funkcja;
            formWykres2D.Wykres.narysujFunkcje();
            formWykres2D.Show();
        }
        private void poprzedniePokolenieWykres2D()
        {
            formWykres2D.Wykres.ListaPunktow = poprzedniaPopulacjaHistorii();
            formWykres2D.Wykres.narysujPunkty();
            formWykres2D.Refresh();
        }

        private void nastepnePokolenieWykres2D()
        {
            formWykres2D.Wykres.ListaPunktow = nastepnaPopulacjaHistorii();
            formWykres2D.Wykres.narysujPunkty();
            formWykres2D.Refresh();
        }

        private void poczatkowePokolenieWykres2D()
        {
            formWykres2D.Wykres.ListaPunktow = poczatkowaPopulacjaHistorii();
            formWykres2D.Wykres.narysujPunkty();
            formWykres2D.Refresh();
        }

        private void koncowePokolenieWykres2D()
        {
            formWykres2D.Wykres.ListaPunktow = koncowaPopulacjaHistorii();
            formWykres2D.Wykres.narysujPunkty();
            formWykres2D.Refresh();
        }
        private void zamknijWykres2D()
        {
            formWykres2D.Close();
        }
        #endregion

        #region Wykres 3D
        private void pokazWykres3D()
        {
            formWykres3D = new FormWykres3D();
            formWykres3D.Wykres.PoczatekDziedziny = new PointF((float)userControlParametry.PoczatekDziedziny[0], (float)userControlParametry.PoczatekDziedziny[1]);
            formWykres3D.Wykres.KoniecDziedziny = new PointF((float)userControlParametry.KoniecDziedziny[0], (float)userControlParametry.KoniecDziedziny[1]);
            formWykres3D.Wykres.Funkcja = userControlParametry.Funkcja.ToString();
            formWykres3D.Wykres.RysujKonturyNaPowierzchni = true;
            formWykres3D.Wykres.ListaPunktow = new List<Point3D>();
            formWykres3D.Show();
        }
        private void nastepnePokolenieWykres3D()
        {
            formWykres3D.Wykres.ListaPunktow = nastepnaPopulacjaHistorii();
            formWykres3D.Wykres.Refresh();
        }
        private void poprzedniePokolenieWykres3D()
        {
            formWykres3D.Wykres.ListaPunktow = poprzedniaPopulacjaHistorii();
            formWykres3D.Wykres.Refresh();
        }
        private void poczatkowePokolenieWykres3D()
        {
            formWykres3D.Wykres.ListaPunktow = poczatkowaPopulacjaHistorii();
            formWykres3D.Wykres.Refresh();
        }
        private void koncowePokolenieWykres3D()
        {
            formWykres3D.Wykres.ListaPunktow = koncowaPopulacjaHistorii();
            formWykres3D.Wykres.Refresh();
        }
        private void zamknijWykres3D()
        {
            formWykres3D.Close();
        }
        #endregion

        #region Przechodzenie po historii populacji

        private List<Point3D> nastepnaPopulacjaHistorii()
        {
            var historiaPopulacji = algorytmGenetyczny.Historia.ListaPopulacji;
            indeksPopulacjiHistorii++;
            if (indeksPopulacjiHistorii > historiaPopulacji.Count - 1)
            {
                indeksPopulacjiHistorii = historiaPopulacji.Count - 1;
            }
            return konwertujPopulacjeHistorii(historiaPopulacji[indeksPopulacjiHistorii]);
        }

        private List<Point3D> poprzedniaPopulacjaHistorii()
        {
            var historiaPopulacji = algorytmGenetyczny.Historia.ListaPopulacji;
            indeksPopulacjiHistorii--;
            if (indeksPopulacjiHistorii < 0)
            {
                indeksPopulacjiHistorii = 0;
            }
            return konwertujPopulacjeHistorii(historiaPopulacji[indeksPopulacjiHistorii]);
        }

        private static List<Point3D> konwertujPopulacjeHistorii(PopulacjaHistoria populacjaHistorii)
        {
            List<Point3D> listaPunktow = new List<Point3D>();
            foreach (OsobnikHistoria osobnik in populacjaHistorii.Osobnicy)
            {
                listaPunktow.Add(osobnik.Punkt);
            }
            return listaPunktow;
        }

        private List<Point3D> poczatkowaPopulacjaHistorii()
        {
            var historiaPopulacji = algorytmGenetyczny.Historia.ListaPopulacji;
            indeksPopulacjiHistorii = 0;
            return konwertujPopulacjeHistorii(historiaPopulacji[indeksPopulacjiHistorii]);
        }

        private List<Point3D> koncowaPopulacjaHistorii()
        {
            var historiaPopulacji = algorytmGenetyczny.Historia.ListaPopulacji;
            indeksPopulacjiHistorii = historiaPopulacji.Count - 1;
            return konwertujPopulacjeHistorii(historiaPopulacji[indeksPopulacjiHistorii]);
        }

        #endregion

    }
}
